// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************
#include "mk_header.h"
#include "mk_skeleton_data.h"
#include "mk_skeleton_data_loader.h"
#include "mk_memory_block.h"
#include "mk_error.h"
#include "mk_file_system.h"

namespace MK3DE
{
	CSkeletonData::CSkeletonData(const char* fileName) : CResource(fileName)
	{
		_header = NULL;
		_boneHeaders = NULL;
	}

	CSkeletonData::~CSkeletonData()
	{

	}

	void CSkeletonData::__Clean()
	{
		_header = NULL;
		_boneHeaders = NULL;
	}

	BOOL CSkeletonData::Load()
	{
		BOOL ret = FALSE;

		ret = GetEngine()->GetFileSystem()->ReadFile(_fileName.c_str(), &_dataBlock);
		MK_PROCESS_ERROR(ret);

		BYTE* data = _dataBlock.GetBuffer();
		_header = (Header*)data;
		MK_PROCESS_ERROR(_header->id == MK_SKELETON_ID);
		MK_PROCESS_ERROR(_header->frameNum > 0);
		MK_PROCESS_ERROR(_header->boneNum > 0);
		MK_PROCESS_ERROR(_header->offsetBoneData != 0);

		_boneHeaders = (BoneHeader*)(data + _header->offsetBoneData);
		MK_PROCESS_ERROR((_header->offsetBoneData + sizeof(BoneHeader) * _header->boneNum) <= _dataBlock.GetSize());

		for (WORD i = 0; i < _header->boneNum; ++i)
		{
			BoneHeader& boneHeader = _boneHeaders[i];
			MK_PROCESS_ERROR((boneHeader.offsetTranslation + sizeof(D3DXVECTOR3) * boneHeader.translationNum) <= _dataBlock.GetSize());
			MK_PROCESS_ERROR((boneHeader.offsetRotation + sizeof(D3DXQUATERNION) * boneHeader.rotationNum) <= _dataBlock.GetSize());
			MK_PROCESS_ERROR((boneHeader.offsetScale + sizeof(D3DXVECTOR3) * boneHeader.scaleNum) <= _dataBlock.GetSize());
			MK_PROCESS_ERROR((boneHeader.offsetScaleRotation + sizeof(D3DXQUATERNION) * boneHeader.scaleRotationNum) <= _dataBlock.GetSize());
		}

		ret = TRUE;
Exit0:
		if (!ret)
			__Clean();

		return ret;
	}

	BOOL CSkeletonData::GetBoneName(DWORD boneIdx, std::string& name)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		name.assign(boneHeader->name);
		return TRUE;
	}

	BOOL CSkeletonData::GetParentIdx(DWORD boneIdx, WORD& parentIdx)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		parentIdx = boneHeader->parentIdx;
		return TRUE;
	}

	BOOL CSkeletonData::GetTranslationKey(DWORD boneIdx, DWORD keyIdx, D3DXVECTOR3& translation, BOOL& animation)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BYTE* data = _dataBlock.GetBuffer();
		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		if (boneHeader->translationNum == 1)
		{
			D3DXVECTOR3* t = (D3DXVECTOR3*)(data + boneHeader->offsetTranslation);
			translation = t[0];
			animation = FALSE;
			return TRUE;
		}
		else if (boneHeader->translationNum > keyIdx)
		{
			D3DXVECTOR3* t = (D3DXVECTOR3*)(data + boneHeader->offsetTranslation);
			translation = t[keyIdx];
			animation = TRUE;
			return TRUE;
		}

		return FALSE;
	}

	BOOL CSkeletonData::GetRotationKey(DWORD boneIdx, DWORD keyIdx, D3DXQUATERNION& rotation, BOOL& animation)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BYTE* data = _dataBlock.GetBuffer();
		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		if (boneHeader->rotationNum == 1)
		{
			D3DXQUATERNION* q = (D3DXQUATERNION*)(data + boneHeader->offsetRotation);
			rotation = q[0];
			animation = FALSE;
			return TRUE;
		}
		else if (boneHeader->rotationNum > keyIdx)
		{
			D3DXQUATERNION* q = (D3DXQUATERNION*)(data + boneHeader->offsetRotation);
			rotation = q[keyIdx];
			animation = TRUE;
			return TRUE;
		}

		return FALSE;
	}

	BOOL CSkeletonData::GetScaleKey(DWORD boneIdx, DWORD keyIdx, D3DXVECTOR3& scale, BOOL& animation)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BYTE* data = _dataBlock.GetBuffer();
		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		if (boneHeader->scaleNum == 1)
		{
			D3DXVECTOR3* s = (D3DXVECTOR3*)(data + boneHeader->offsetScale);
			scale = s[0];
			animation = FALSE;
			return TRUE;
		}
		else if (boneHeader->scaleNum > keyIdx)
		{
			D3DXVECTOR3* s = (D3DXVECTOR3*)(data + boneHeader->offsetScale);
			scale = s[keyIdx];
			animation = TRUE;
			return TRUE;
		}

		return FALSE;
	}

	BOOL CSkeletonData::GetScaleRotationKey(DWORD boneIdx, DWORD keyIdx, D3DXQUATERNION& scaleRotation, BOOL& animation)
	{
		if (boneIdx >= _header->boneNum)
			return FALSE;

		BYTE* data = _dataBlock.GetBuffer();
		BoneHeader* boneHeader = &_boneHeaders[boneIdx];
		if (boneHeader->scaleRotationNum == 1)
		{
			D3DXQUATERNION* sr = (D3DXQUATERNION*)(data + boneHeader->offsetScaleRotation);
			scaleRotation = sr[0];
			animation = FALSE;
			return TRUE;
		}
		else if (boneHeader->scaleRotationNum > keyIdx)
		{
			D3DXQUATERNION* sr = (D3DXQUATERNION*)(data + boneHeader->offsetScaleRotation);
			scaleRotation = sr[keyIdx];
			animation = TRUE;
			return TRUE;
		}

		return FALSE;
	}
}